//
//  PhoneCodeLoginViewModel.swift
//  User
//
//  Created by ET|冰琳 on 2017/1/9.
//  Copyright © 2017年 IB. All rights reserved.
//

import Foundation
import ReactiveSwift

public enum PhoneCodeLoginError: Error {
    case phoneInvalide
    case codeInvalide
    case error(msg: String)
}

/// 手机号 验证码登录
/// login with phone and verify code
open class PhoneCodeLoginViewModel<T: PhoneCodeLoginService>: NSObject {
    
    open var phone = MutableProperty<String?>(nil)
    open var code  = MutableProperty<String?>(nil)
    
    open var phoneValide = MutableProperty(false)
    open var codeValide  = MutableProperty(false)
    
    open var phoneValidator: Validator?
    open var verifyCodeValidator: Validator?

    private var service: T
    
    open var getCode: Action<(), T.PhoneCodeResult, PhoneCodeLoginError>!
    open var login:   Action<(), T.PhoneCodeLoginResult, PhoneCodeLoginError>!
    
    /// - Parameter service: PhoneCodeLoginService
    public init(service: T) {
        self.service = service
        super.init()
        self.bind()
    }
    
    /// - private
    private func bind() {
        
        // valide
        phoneValide <~ phone.signal.map({
            let validator = self.phoneValidator ?? PhoneValidator()
            return validator.validate(txt: $0)
        })
        
        codeValide <~ code.signal.map({
            let validator = self.verifyCodeValidator ?? DefaultValidator()
            return validator.validate(txt: $0)
        })
        
        // action
        getCode = Action { return self.getCodeSignal() }
        
        login = Action { return self.loginSignal() }
    }
    
    private func getCodeSignal() -> SignalProducer<T.PhoneCodeResult, PhoneCodeLoginError> {
        
        guard phoneValide.value else {
            return SignalProducer(error: .phoneInvalide)
        }
        
        return self.service.getVerifyCodeOf(phone: self.phone.value)
            .flatMapError({ (err) -> SignalProducer<T.PhoneCodeResult, PhoneCodeLoginError> in
                return SignalProducer(error: .error(msg: err.localizedDescription))
            })
    }
    
    private func loginSignal() -> SignalProducer<T.PhoneCodeLoginResult, PhoneCodeLoginError> {
        
        guard phoneValide.value else {
            return SignalProducer(error: .phoneInvalide)
        }
        
        guard codeValide.value else {
            return SignalProducer(error: .codeInvalide)
        }
        
        return self.service.loginWith(phone: self.phone.value, code: self.code.value)
            .flatMapError({ (err) -> SignalProducer<T.PhoneCodeLoginResult, PhoneCodeLoginError> in
                return SignalProducer(error: .error(msg: err.localizedDescription))
            })
    }
}
